package centroidtc;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

/**
 *  Handle different tasks
 */
public class TCTool {
	// train and test set
	private ArrayList<String> trainFileIdList = null;
	private ArrayList<String> testFileIdList = null;
	// get category's information
	private TextPaser pCorpus = null;
	private CentroidBuilder cb = null;
	
	public TCTool() {
		pCorpus = new TextPaser();
		cb = new CentroidBuilder();
		
		getTrainTestSet();
		writeCatName();
	}
	
	/**
	 * save testing stat info into files for CFC classifiers
	 */
	public void saveCFCTestStatInfo() {
		String testFileName = "out" + File.separator + "centroid_test_sim.txt";
		// get the the threshold array
		ArrayList<Double> threshold = this.getCatThreshold();
		// get test array
		ArrayList<ArrayList<Double>> test = this.getArrFromFile(testFileName);
		
		FileManager testVector = new FileManager("test_centroid_stat_result.txt");
		ArrayList<Double> rec = new ArrayList<Double>();
		ArrayList<Integer> recTmp = new ArrayList<Integer>();
		String[] ta = null;
		int catNum = 0;
		int total_num = 0;
		int total_tp = 0;
		int total_fn = 0;
		int total_fp = 0;
		double tm_f1 = 0.0;
		int tm_count =0;
		for (int j = 0; j < pCorpus.subClassItems.size(); j++) {
			// get the index array
			for (String d_id : this.testFileIdList) {
				ta = d_id.split("-");
				int catNumber = Integer.parseInt(ta[0]);
				if (catNumber == (catNum+1)) {
					int res_index = testFileIdList.indexOf(d_id);
					recTmp.add(res_index);
				}
			}
			rec.add((double)recTmp.size());
			// get this category's classification result
			ArrayList<Double> catResult = test.get(catNum);
			// get the stat of classification info
			int tp = 0;
			int fp = 0;
			int fn = 0;
			for (int i = 0; i < catResult.size(); i++) {
				double e = catResult.get(i) - threshold.get(catNum);
				if ((e >= 0.0)&&(recTmp.contains(i))) {
					tp++;
				}
				if ((e < 0.0)&&(recTmp.contains(i))) {
					fn++;
				}
				if ((e >= 0.0)&&(!recTmp.contains(i))) {
					fp++;
				}
			}
			total_num += recTmp.size();
			total_tp += tp;
			total_fn += fn;
			total_fp += fp;
			rec.add((double)tp);
			rec.add((double)fn);
			rec.add((double)fp);
			double precision = ((double)tp)/((double)(tp+fp));
			double recall = ((double)tp)/((double)(tp+fn));
			double f1 = 2*recall*precision/(recall + precision);
			tm_f1 += f1;
			tm_count++;
			rec.add(precision);
			rec.add(recall);
			rec.add(f1);
			
			// write out the record
			testVector.writeArrayIntoFile(rec, ",");
			
			rec.clear();
			recTmp.clear();
			catNum++;
		}
		rec.add((double)total_num);
		rec.add((double)total_tp);
		rec.add((double)total_fn);
		rec.add((double)total_fp);
		double p_t = ((double)total_tp)/((double)(total_tp+total_fp));
		double r_t = ((double)total_tp)/((double)(total_tp+total_fn));
		double f1_t = 2*p_t*r_t/(r_t + p_t);
		rec.add(p_t);
		rec.add(r_t);
		rec.add(f1_t);
		testVector.writeArrayIntoFile(rec, ",");
		rec.clear();
		
		rec.add((double)total_num);
		rec.add((double)total_tp);
		rec.add((double)total_fn);
		rec.add((double)total_fp);
		rec.add(p_t);
		rec.add(r_t);
		
		rec.add(tm_f1/tm_count);
		testVector.writeArrayIntoFile(rec, ",");
		rec.clear();
		
		
		testVector.closeWriter();
	}
	
	/**
	 * get the categories' threshold from an array
	 */
	private ArrayList<Double> getCatThreshold(){
		ArrayList<Double> ret = null;
		ret = new ArrayList<Double>();
		for (int i = 0; i < pCorpus.subClassItems.size(); i++) {
			ret.add(1.0);
		}
		return ret;
	}
	
	/**
	 * get the categories' threshold from an array
	 */
	private void writeCatName(){
		FileManager aWriter = new FileManager("categorizeslist.txt");
		for (int i = 0; i < pCorpus.subClassItems.size(); i++) {
			String s = pCorpus.subClassItems.get(i).getClassName();
			aWriter.writeBigStringIntoFile(s);
		}
		aWriter.closeWriter();
		return;
	}
	
	/**
	 * change a train result file into an array
	 */
	private ArrayList<ArrayList<Double>> getArrFromFile(String fileName){
		ArrayList<ArrayList<Double>> ret = new ArrayList<ArrayList<Double>>();
		for (int i = 0; i < pCorpus.subClassItems.size(); i++) {
			ArrayList<Double> arr = new ArrayList<Double>();
			ret.add(arr);
		}
		BufferedReader in = null;
		try {
			in = new BufferedReader(new FileReader(fileName));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		String s = null;
		ArrayList<Double> tmpArray = new ArrayList<Double>();
		try {
			while ((s = in.readLine()) != null) {
				String ts = s.trim();
				String [] ta = ts.split(",");
				for (int i = 0; i < ta.length; i++) {
					if (!ta[i].trim().equalsIgnoreCase("")) {
						tmpArray.add(Double.parseDouble(ta[i]));
					}
				}
				for (int i = 0; i < tmpArray.size(); i++) {
					ret.get(i).add(tmpArray.get(i));
				}
				tmpArray.clear();
			}
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return ret;
	}
	
	/**
	 * get training and testing set
	 */
	private void getTrainTestSet(){
		trainFileIdList = new ArrayList<String>();
		testFileIdList = new ArrayList<String>();
		// we get the training and testing set in the same sequence
		String fileName = "out" + File.separator + "20-newsgroup_vector.txt";
		BufferedReader in = null;
		try {
			in = new BufferedReader(new FileReader(fileName));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		String s = null;
		String [] ta = null;
		int winnow = 0;
		try {
			while ((s = in.readLine()) != null) {
				ta = s.trim().split("::");
				if ((winnow % 3) <= 1) {
					trainFileIdList.add(ta[0]);
				}
				if ((winnow % 3) > 1) {
					testFileIdList.add(ta[0]);
				}
				winnow++;
			}
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	public static void main(String[] args) {
		TCTool t = new TCTool();
		t.saveCFCTestStatInfo();
		System.out.println("testing set's size: "+t.testFileIdList.size());
		System.out.println("training set's size: "+t.trainFileIdList.size());
	}
}
